﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace cvtest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        ///图片翻转
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartButton_Click(object sender, EventArgs e)
        {
            MatFlip();
            GC.Collect();
        }

        /// <summary>
        ///图片翻转
        /// </summary>
        public void MatFlip()
        {
            string imagepath = "C:/Users/1920.JPG";
            try
            {
                Mat image = Readpicture(imagepath);

                //创建一个图片文件
                //Cv2.ImRead(imagepath);//读取输入图像
                //Cv2.NamedWindow("demo", WindowMode.KeepRatio);//定义显示图像的窗口大小，WindowsMode.autosize将窗口大小根据图片来定义

                #region Flip说明

                /*
                 摘要:
                     Specifies how to flip the array
                 摘要:
                     means flipping around both axises
                XY = -1,
                 摘要:
                     means flipping around x-axis
                X = 0,
                 摘要:
                     means flipping around y-axis
                Y = 1
                */

                #endregion Flip说明

                Mat result = new Mat();
                Cv2.Flip(image, result, FlipMode.Y);//Flip 翻转图片
                Cv2.NamedWindow("demo2", WindowMode.KeepRatio);
                Cv2.ImShow("demo2", result);
                Cv2.WaitKey();
                Cv2.DestroyWindow("demo2");
                Cv2.DestroyAllWindows();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                //throw;
            }
            GC.Collect();
        }

        /// <summary>
        ///图片上画圈、写字
        /// </summary>
        public void MatDrawing()
        {
            string imagepath = "C:/Users/1920.JPG";
            Mat image = Readpicture(imagepath);//创建一个图片文件
                                               //#region CV2.Circle说明

            #region CV2.Circle说明

            // 摘要:
            //     Draws a circle
            //
            // 参数:
            //   img:
            //     Image where the circle is drawn.
            //
            //   centerX:
            //     X-coordinate of the center of the circle.
            //
            //   centerY:
            //     Y-coordinate of the center of the circle.
            //
            //   radius:
            //     Radius of the circle.
            //
            //   color:
            //     Circle color.
            //
            //   thickness:
            //     Thickness of the circle outline if positive, otherwise indicates that a filled
            //     circle has to be drawn. [By default this is 1]
            //
            //   lineType:
            //     Type of the circle boundary. [By default this is LineType.Link8]
            //
            //   shift:
            //     Number of fractional bits in the center coordinates and radius value. [By default
            //     this is 0]

            #endregion CV2.Circle说明

            Cv2.Circle(image, 500, 600, 200, 0, 3);

            #region PutText参数介绍

            //
            // 摘要:
            //     renders text string in the image
            //
            // 参数:
            //   img:
            //
            //   text:
            //
            //   org:OpenCvSharp.Point org = new OpenCvSharp.Point(int x, int y);
            //
            //   fontFace:字体类型
            //
            //   fontScale:字体大小
            //
            //   color:字体颜色
            //
            //   thickness:字体厚度
            //
            //   lineType:
            //
            //   bottomLeftOrigin:

            #endregion PutText参数介绍

            OpenCvSharp.Point org = new OpenCvSharp.Point(460, 860);
            Cv2.PutText(image, "this is sekiro", org, HersheyFonts.HersheyComplex, 4.0, 255, 2);
            Cv2.NamedWindow("demo2", WindowMode.KeepRatio);
            Cv2.ImShow("demo2", image);
            Cv2.WaitKey();
            Cv2.DestroyAllWindows();
            GC.Collect();
        }

        /// <summary>
        /// 在图片中插入图片
        /// </summary>
        public void MatCopy()
        {
            string imagepath = "C:/Users/1920.JPG";
            Mat image = Readpicture(imagepath);
            Mat logo = Readpicture("C:/Users/logo.JPG");
            Rect rectroi = new Rect(image.Cols - logo.Cols, image.Rows - logo.Rows, logo.Cols, logo.Rows);
            Mat imageroi = new Mat(image, rectroi);
            //Cv2.NamedWindow("demo2", WindowMode.KeepRatio);
            //Cv2.ImShow("demo2", imageroi);
            logo.CopyTo(imageroi);
            //ROI 实际上就是一个cv::Mat 对象，它与它的父图像指向同一个数据缓冲区，并且在头
            //部指明了ROI 的坐标。
            Cv2.NamedWindow("demo1", WindowMode.KeepRatio);
            Cv2.ImShow("demo1", image);
            Cv2.WaitKey();
            ////void CopyTo(Mat roi, Mat mask);
            ////注意mask的数据类型，必须是CV_8U，且通道数或者是1，或者与roi一致。
            //logo.CopyTo(imageroi);//logo的内容复制粘贴到imageROI上；
            Cv2.DestroyAllWindows();
            GC.Collect();
        }

        /// <summary>
        /// 一个外部调用的读取图片方法，返回Mat 图片
        /// </summary>
        /// <param name="str">图片路径</param>
        /// <returns></returns>
        public Mat Readpicture(string str)
        {
            try
            {
                if (str.Length == 0)
                {
                    MessageBox.Show("图片路径错误");
                    return null;
                }
                else
                {
                    Mat image = new Mat(@str, ImreadModes.Color);
                    //Mat image = new Mat(@str, ImreadModes.Grayscale);//将图片转变为灰度图像

                    return image;
                }
            }
            catch (Exception)
            {
                return null;
                throw;
            }
        }

        /// <summary>
        /// 在图片上画圈、写字
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            MatDrawing();
            GC.Collect();
        }

        /// <summary>
        ///在图片上插入新图像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            MatCopy();
            GC.Collect();
        }

        /// <summary>
        ///copyto(m,mask) 只将mask中像素值不为0的部分作为掩码插入图片m
        /// </summary>
        public void MatMask()
        {
            Mat image = Readpicture("C:/Users/1920.JPG");
            Mat logo = Readpicture("C:/Users/logo.JPG");
            Rect rectroi = new Rect(image.Cols - logo.Cols, image.Rows - logo.Rows, logo.Cols, logo.Rows);
            Mat imageroi = new Mat(image, rectroi);
            logo.CopyTo(imageroi, logo);
            //插入掩码，只复制掩码不为0 的位置
            Cv2.NamedWindow("demo1", WindowMode.KeepRatio);
            Cv2.ImShow("demo1", image);
            Cv2.WaitKey();
            Cv2.DestroyAllWindows();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            MatMask();
            GC.Collect();
        }

        /// <summary>
        /// 用它在图像中加入椒盐噪声（salt-and-pepper noise）。顾名思义，椒盐噪声是一个专门的噪声类型
        /// 它随机选择一些像素，把它们的颜色替换成白色或黑色。
        /// 如果通信时出错，部分像素的值在传输时丢失，就会产生这种噪声。
        /// 这里只是随机选择一些像素，把它们设置为白色。
        /// </summary>
        public void SaltPepperNoisy()
        {
            Mat mat = Readpicture("C:/Users/1920.JPG");
            Random random = new Random();
            int n = int.Parse(textBox1.Text);
            int j, k;
            for (int i = 0; i < n; i++)
            {
                j = random.Next(0, mat.Rows - 1);
                k = random.Next(0, mat.Cols - 1);
                //如果是单通道灰色图像，char black = (char)0;
                //char white = (char)0;
                //如果是彩色图片，因为彩图是3通道，所以要Vec3b white = new Vec3b(255, 255, 255);
                Vec3b white = new Vec3b(255, 255, 255);
                mat.Set(j, k, white);
            }
            WindowsShow(mat, "salt&pepper");
            //Cv2.NamedWindow("salt&pepper", WindowMode.KeepRatio);
            //Cv2.ImShow("salt&pepper", mat);
            //Cv2.WaitKey();
            Cv2.DestroyAllWindows();
            GC.Collect();
        }

        /// <summary>
        /// 将传入图片进行椒盐噪声处理，对随机像素点设置为白色
        /// </summary>
        /// <param name="mat"></param>
        public void SaltPepperNoisy(Mat mat)
        {
            Random random = new Random();
            int n = int.Parse(textBox1.Text);
            int j, k;
            for (int i = 0; i < n; i++)
            {
                j = random.Next(0, mat.Rows);
                k = random.Next(0, mat.Cols);
                Vec3b white = new Vec3b(255, 255, 255);
                mat.Set(j, k, white);
            }
        }

        /// <summary>
        /// 椒盐噪声算法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            SaltPepperNoisy();
            GC.Collect();
        }

        public void CtrlPixel()
        {
            Mat mat = Readpicture("C:/Users/1920.JPG");
            Mat mat1 = new Mat();
            mat.CopyTo(mat1);
            for (int i = 0; i < mat.Rows; i++)
            {
                for (int j = 0; j < mat.Cols; j++)
                {
                    //如果是灰色图像
                    //byte color = (byte)Math.Abs(mat.Get<byte>(i, j) - 50);//读取原来的通道值并减50
                    //mat.Set(i, j, color);
                    Vec3b color = new Vec3b();
                    color.Item0 = (byte)Math.Abs((mat.Get<Vec3b>(i, j).Item0 - 50));
                    color.Item1 = (byte)Math.Abs((mat.Get<Vec3b>(i, j).Item1 - 50));
                    color.Item2 = (byte)Math.Abs((mat.Get<Vec3b>(i, j).Item2 - 50));
                    mat.Set(i, j, color);
                }
            }
            WindowsShow(mat, "处理后");
            WindowsShow(mat1, "原图");
            GC.Collect();
        }

        /// <summary>
        /// 操作像素点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            CtrlPixel();
            GC.Collect();
        }

        /// <summary>
        /// 窗口展示图片
        /// </summary>
        /// <param name="mat">图片文件名</param>
        /// <param name="str1">窗口名</param>
        //private void WindowsShow(Mat mat, string str1)
        //{
        //    Cv2.NamedWindow(str1, WindowMode.KeepRatio);
        //    Cv2.ImShow(str1, mat);
        //    //Cv2.NamedWindow("处理后", WindowMode.KeepRatio);
        //    //Cv2.ImShow("处理后", mat1);
        //    Cv2.WaitKey();
        //    Cv2.DestroyAllWindows();
        //}

        private async Task WindowsShow(Mat mat, string str1)
        {
            await Task.Delay(200);
            Cv2.NamedWindow(str1, WindowMode.KeepRatio);
            Cv2.ImShow(str1, mat);
            //Cv2.NamedWindow("处理后", WindowMode.KeepRatio);
            //Cv2.ImShow("处理后", mat1);
            Cv2.WaitKey();
            Cv2.DestroyAllWindows();
            GC.Collect();
        }

        /// <summary>
        /// 均值滤波，使图像边缘模糊、柔和
        /// 从频率域观点来看均值滤波是一种低通滤波器，
        /// 高频信号将会去掉，因此可以帮助消除图像尖锐噪声，实现图像平滑，模糊等功能。
        /// </summary>
        public void Blurtest()
        {
            Mat mat = Readpicture("C:/Users/1920.JPG");
            Mat mat1 = new Mat();
            mat.CopyTo(mat1);
            Cv2.Blur(mat, mat, new OpenCvSharp.Size(5, 5));
            //WindowsShow(mat, "处理后");
            //WindowsShow(mat1, "原图");
            Cv2.NamedWindow("处理后", WindowMode.KeepRatio);
            Cv2.ImShow("处理后", mat);
            Cv2.WaitKey();
            Cv2.DestroyAllWindows();
            //使用异步显示窗口后，程序内存会变大，会不会是因为线程池的问题？
            GC.Collect();
        }

        /// <summary>
        /// 均值滤波
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button6_Click(object sender, EventArgs e)
        {
            Blurtest();
            GC.Collect();
        }

        /// <summary>
        /// 先椒盐噪声，再对图片进行中值滤波处理
        /// 中值滤波法对消除椒盐噪声非常有效，在光学测量条纹图象的相位分析处理方法中有特殊作用，
        /// 但在条纹中心分析方法中作用不大.
        /// 中值滤波在图像处理中,常用于保护边缘信息,是经典的平滑噪声的方法。
        /// 中值滤波是跟均值滤波唯一不同是，不是用均值来替换中心每个像素，而是将周围像素和中心像素排序以后，取中值
        /// </summary>
        public void medianBlurtest()
        {
            Mat mat = Readpicture("C:/Users/1920.JPG");
            Mat mat1 = new Mat();
            SaltPepperNoisy(mat);
            mat.CopyTo(mat1);
            Cv2.MedianBlur(mat, mat, 3);
            WindowsShow(mat, "处理后");//中值滤波后
            WindowsShow(mat1, "原图");//椒盐噪声
            GC.Collect();
        }

        private void button7_Click(object sender, EventArgs e)
        {
            medianBlurtest();
            GC.Collect();
        }

        /// <summary>
        /// 高斯滤波后图像被平滑的程度取决于标准差。它的输出是领域像素的加权平均，同时离中心越近的像素权重越高。因此，相对于均值滤波（mean filter）它的平滑效果更柔和，而且边缘保留的也更好。
        /// </summary>
        public void GaussBlur()
        {
            Mat mat = Readpicture("C:/Users/1920.JPG");
            Mat mat1 = new Mat();
            mat.CopyTo(mat1);
            Cv2.GaussianBlur(mat, mat, new OpenCvSharp.Size(3, 5), 0);
            WindowsShow(mat, "处理后");//高斯滤波后
            WindowsShow(mat1, "原图");//
            GC.Collect();
        }

        /// <summary>
        /// 高斯滤波
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button8_Click(object sender, EventArgs e)
        {
            GaussBlur();
            GC.Collect();
        }

        public void BilaterlBlur()
        {
            Mat mat = Readpicture("C:/Users/1920.JPG");
            Mat mat1 = new Mat();
            mat.CopyTo(mat1);
            Cv2.BilateralFilter(mat, mat, 5, 10, 2);
            //Cv2.GaussianBlur(mat, mat, new OpenCvSharp.Size(3, 5), 0);
            WindowsShow(mat, "处理后");//高斯滤波后
            WindowsShow(mat1, "原图");//
            GC.Collect();
        }

        /// <summary>
        /// 调用双边滤波方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button9_Click(object sender, EventArgs e)
        {
            BilaterlBlur();
            GC.Collect();
        }
    }
}